<!DOCTYPE html>
<html>
<head>
    <!--Import Google Icon Font-->
    <link type="text/css" rel="stylesheet" href="css/material-icons.css"/>
    <!--Import materialize.css-->
    <link type="text/css" rel="stylesheet" href="css/materialize.min.css" media="screen,projection"/>
    <title>Users</title>

    <!--Let browser know website is optimized for mobile-->
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>

<div class="container">
  <div class="row">
    <div class="col s4 m2 l2">
      <div class="collection" id="sub-menu">
      </div>
    </div>
    <div class="col s8 m10 l10">
      <div id="content">
      </div>
    </div>
  </div>
  <div class="modal" id="user-modal">
      <div class="modal-content" id="modal-content">
      </div>
      <div class="modal-footer">
          <a href="#" class="modal-close waves-effect waves-green btn-flat"></a>
          <a href="#" class="modal-close waves-effect waves-green btn-flat" id="modal-confirm"></a>
      </div>
  </div>
</div>

<!--JavaScript at end of body for optimized loading-->
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="js/materialize.min.js"></script>
<script type="text/javascript" src="js/nano.js"></script>
<script>
    N.ValidateSession();
    var texts = N.GetTexts();
    var nameExp = new RegExp('[^\\w-.]');
    var menuList = N.GetAllMenus();


    $(function(){
      $('.modal-footer > a:first-child').text(texts.get(N.TagCancel));
      $('.modal-footer > a:last-child').text(texts.get(N.TagConfirm));
      //sub menu
      $('#sub-menu').append(
        $('<a>').attr('href', '#').addClass('collection-item').text(texts.get(N.TagUser)).attr('onclick', 'loadUsers()')
      ).append(
        $('<a>').attr('href', '#').addClass('collection-item').text(texts.get(N.TagUserGroup)).attr('onclick', 'loadGroups()')
      ).append(
        $('<a>').attr('href', '#').addClass('collection-item').text(texts.get(N.TagRole)).attr('onclick', 'loadRoles()')
      );
      M.AutoInit();
      M.Modal.init($('.modal'));
      loadUsers();
    });


    function loadUsers(){
      var panel = $('#content').empty();
      panel.append(
        $('<div>').addClass('section').append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('col s4 m3 l2').append(
              $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('href', '#').attr('onclick', 'showCreateUser()').append(
                $('<i>').addClass('material-icons left').text('add')
              ).append(
                texts.get(N.TagCreate)
              )
            )
          )
        )
      ).append(
        $('<div>').addClass('divider')
      );
      var userList = $('<div>').attr('id', 'user-list');
      panel.append(
        userList
      );
      function outputMessage(message){
        userList.empty().append(
          $('<div>').addClass('center').append(
            $('<span>').text(message)
          )
        );
      }

      $.getJSON(
        '/users/',
        function(result){
          if (0 != result['error_code']) {
            outputMessage(result['message']);
            return;
          }
          if (!result['data']){
            outputMessage('no user available');
            return
          }
          if (0 == result['data'].length){
            outputMessage('no user available');
            return;
          }
          var container = $('<div>').addClass('row');
          var table = $('<table>').append(
            $('<thead>').append(
              $('<tr>').append(
                $('<td>').text(texts.get(N.TagUser))
              ).append($('<td>'))
            )
          );
          var currentUser = N.GetCurrentUser();
          result['data'].forEach((name) => {
            var content = $('<tr>');
            content.append(
              $('<td>').text(name)
            );
            var operators = $('<td>');
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'bottom').
                attr('data-tooltip', texts.get(N.TagModify)).attr('onclick', 'showModifyUser("'+ name +'")').append(
                  $('<i>').addClass('material-icons').text('build')
                )
            );
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'bottom').
                attr('data-tooltip', texts.get(N.TagPassword)).attr('onclick', 'showModifyPassword("'+ name +'")').append(
                  $('<i>').addClass('material-icons').text('lock')
                )
            );
            if (name != currentUser){
              operators.append(
                $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'bottom').
                  attr('data-tooltip', texts.get(N.TagDelete)).attr('onclick', 'showDeleteUser("'+ name +'")').append(
                    $('<i>').addClass('material-icons').text('delete')
                  )
              );
            }

            content.append(operators);
            container.append(
              $('<div>').addClass('col m8 push-m2').append(
                table.append(content)
              )
            );
          });
          userList.empty().append(container);
          $('.material-tooltip').remove();
          M.Tooltip.init($('.tooltipped'));
        }
      );
    }

    function showCreateUser(){
      loadUserInput();
      $('#user-button').attr('onclick', 'createUser()').append(
        $('<i>').addClass('material-icons right').text('add')
      ).append(
        texts.get(N.TagCreate)
      );
    }

    function createUser(){
      var username = $('#user-name').val();
      if (!username){
        M.toast({html: 'please input username'});
        return;
      }
      if (nameExp.test(username)){
        M.toast({html: "only letter/digit/'-'/'_'/'.' allowed in username"});
        return;
      }
      var password = $('#user-password').val();
      if (!password){
        M.toast({html: 'please input password'});
        return;
      }
      if (password != $('#user-password2').val()){
        M.toast({html: 'two passwords are unmatched.'});
        return;
      }
      var request = new Object();
      request.password = password;
      var nickName = $('#user-nick').val();
      if (nickName){
        request.nick = nickName;
      }
      var mail = $('#user-mail').val();
      if (mail){
        request.mail = mail;
      }
      $.post(
        '/users/'+ username,
        JSON.stringify(request),
        function(result){
          if (0 != result['error_code']) {
            M.toast({html: result['message']});
            return;
          }
          M.toast({html: 'user ' + username + ' created'});
          loadUsers();
          N.WriteOperateLog('create new user ' + username );
        },
        "json"
      );
    }

    function loadUserInput(){
      var panel = $('#content').empty();
      var content = $('<div>').addClass('row').append(
        $('<div>').addClass('col m8 push-m2').append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              $('<input>').attr('type', 'text').attr('id', 'user-name').attr('placeholder', 'Username')
            ).append(
              $('<label>').attr('for', 'user-name').text(texts.get(N.TagUser) + '*')
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              $('<input>').attr('type', 'password').attr('id', 'user-password').attr('placeholder', 'Password')
            ).append(
              $('<label>').attr('for', 'user-password').text(texts.get(N.TagPassword) + '*')
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              $('<input>').attr('type', 'password').attr('id', 'user-password2').attr('placeholder', 'Confirm Password')
            ).append(
              $('<label>').attr('for', 'user-password2').text(texts.get(N.TagPassword) + '*')
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              $('<input>').attr('type', 'text').attr('id', 'user-nick').attr('placeholder', 'Nickname')
            ).append(
              $('<label>').attr('for', 'user-nick').text(texts.get(N.TagNickname))
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              $('<input>').attr('type', 'text').attr('id', 'user-mail').attr('placeholder', 'Mail')
            ).append(
              $('<label>').attr('for', 'user-mail').text(texts.get(N.TagMail))
            )
          )
        )
      );
      var buttons = $('<div>').addClass('row').append(
        $('<div>').addClass('col m2').append(
          $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('onclick', 'loadUsers()').append(
            $('<i>').addClass('material-icons left').text('chevron_left')
          ).append(texts.get(N.TagBack))
        )
      ).append(
        $('<div>').addClass('col m2 right').append(
          $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('id', 'user-button')
        )
      )
      panel.append(
        $('<div>').addClass('section').append(content)
      ).append(
        $('<div>').addClass('divider')
      ).append(
        $('<div>').addClass('section').append(buttons)
      );
      M.updateTextFields();
    }

    function showModifyUser(name){
      $.getJSON(
        '/users/' + name,
        function(result){
          if (0 != result['error_code']) {
            M.toast({html: result['message']});
            return;
          }
          if (!result['data']){
            M.toast({html: 'no user info available'});
            return;
          }
          var user = result['data'];
          var nickname = "";
          if (user['nick']){
            nickname = user['nick'];
          }
          var mail = "";
          if (user['mail']){
            mail = user['mail'];
          }
          $('#modal-content').empty().append(
            $('<h4>').text('Modify User')
          ).append(
            $('<div>').addClass('row').append(
              $('<div>').addClass('input-field col m6').append(
                $('<input>').attr('type', 'text').attr('id', 'user-nick').val(nickname)
              ).append(
                $('<label>').attr('for', 'user-nick').text(texts.get(N.TagNickname))
              )
            )
          ).append(
            $('<div>').addClass('row').append(
              $('<div>').addClass('input-field col m6').append(
                $('<input>').attr('type', 'text').attr('id', 'user-mail').val(mail)
              ).append(
                $('<label>').attr('for', 'user-mail').text(texts.get(N.TagMail))
              )
            )
          );
          M.updateTextFields();
          $('#modal-confirm').attr('onclick', 'modifyUser("' + name + '")');
          var instance = M.Modal.getInstance($('#user-modal'));
          instance.open();
      });

    }

    function modifyUser(name){
      var nickname = $('#user-nick').val();
      var mail = $('#user-mail').val();
      var request = new Object();
      if (nickname){
        request.nick = nickname;
      }
      if (mail){
        request.mail = mail;
      }
      $.ajax({
        url: '/users/'+ name,
        method: "PUT",
        dataType: "json",
        data: JSON.stringify(request),
        success: function (result) {
          if (0 != result['error_code']) {
            M.toast({html: 'modify user fail: ' + result['message']});
            return;
          }
          M.toast({html: 'user ' + name + ' modified'});
          N.WriteOperateLog('modify user ' + name);
        },
        error: function (jqXHR, status, error) {
          M.toast({html: 'request modify user fail: ' + error, outDuration: 600});
        }
      });
    }

    function showModifyPassword(name){
      $('#modal-content').empty().append(
        $('<h4>').text('Modify Password')
      ).append(
        $('<div>').addClass('row').append(
          $('<div>').addClass('input-field col m6').append(
            $('<input>').attr('type', 'password').attr('id', 'old-password')
          ).append(
            $('<label>').attr('for', 'old-password').text(texts.get(N.TagCurrent) + texts.get(N.TagPassword))
          )
        )
      ).append(
        $('<div>').addClass('row').append(
          $('<div>').addClass('input-field col m6').append(
            $('<input>').attr('type', 'password').attr('id', 'user-password')
          ).append(
            $('<label>').attr('for', 'user-password').text(texts.get(N.TagNew) + texts.get(N.TagPassword))
          )
        )
      ).append(
        $('<div>').addClass('row').append(
          $('<div>').addClass('input-field col m6').append(
            $('<input>').attr('type', 'password').attr('id', 'user-password2')
          ).append(
            $('<label>').attr('for', 'user-password2').text(texts.get(N.TagConfirm) + texts.get(N.TagPassword))
          )
        )
      );
      M.updateTextFields();
      $('#modal-confirm').attr('onclick', 'modifyPassword("' + name + '")');
      var instance = M.Modal.getInstance($('#user-modal'));
      instance.open();
    }

    function modifyPassword(name){
      var old = $('#old-password').val();
      if (!old){
        M.toast({html: 'please input current password'});
        return;
      }
      var password = $('#user-password').val();
      if (!password){
        M.toast({html: 'please input new password'});
        return;
      }
      if (password != $('#user-password2').val()){
        M.toast({html: 'two passwords must be the same.'});
        return;
      }

      var request = new Object();
      request.old = old;
      request.new = password;
      $.ajax({
        url: '/users/'+ name + '/password/',
        method: "PUT",
        dataType: "json",
        data: JSON.stringify(request),
        success: function (result) {
          if (0 != result['error_code']) {
            M.toast({html: 'modify password fail: ' + result['message']});
            return;
          }
          M.toast({html: 'password of user ' + name + ' modified'});
          N.WriteOperateLog('modify password of user ' + name);
        },
        error: function (jqXHR, status, error) {
          M.toast({html: 'request modify password fail: ' + error, outDuration: 600});
        }
      });
    }

    function showDeleteUser(name){
      var currentUser = N.GetCurrentUser();
      if (!currentUser){
        M.toast({html: 'invalid current user'});
        return
      }
      if (name == currentUser){
        M.toast({html: 'can not delete current user'});
        return
      }
      $('#modal-content').empty().append(
        $('<h4>').text('Delete User')
      ).append(
        $('<div>').text('Are you sure to delete user ' + name)
      );
      $('#modal-confirm').attr('onclick', 'deleteUser("' + name + '")');
      var instance = M.Modal.getInstance($('#user-modal'));
      instance.open();
    }

    function deleteUser(name) {
      $.ajax({
       url:'/users/' + name,
       type: "DELETE",
       dataType: "json",
       success: function (result) {
           if (0 != result['error_code']) {
               M.toast({html: 'delete user fail: ' + result['message'], outDuration: 1000});
               return;
           }
           M.toast({html: 'user "' + name + '" deleted'})
           setTimeout(loadUsers, 500);
           N.WriteOperateLog('delete user ' + name);
       }
      });
    }

    //roles

    function loadRoles(){
      var panel = $('#content').empty();
      panel.append(
        $('<div>').addClass('section').append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('col s4 m3 l2').append(
              $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('href', '#').attr('onclick', 'showAddRole()').append(
                $('<i>').addClass('material-icons left').text('add')
              ).append(
                texts.get(N.TagAdd)
              )
            )
          )
        )
      ).append(
        $('<div>').addClass('divider')
      );
      var roleList = $('<div>').attr('id', 'role-list');
      panel.append(
        roleList
      );
      function outputMessage(message){
        roleList.empty().append(
          $('<div>').addClass('center').append(
            $('<span>').text(message)
          )
        );
      }

      $.getJSON(
        '/roles/',
        function(result){
          if (0 != result['error_code']) {
            outputMessage(result['message']);
            return;
          }
          if (!result['data']){
            outputMessage('no role available');
            return
          }
          if (0 == result['data'].length){
            outputMessage('no role available');
            return;
          }
          var container = $('<div>').addClass('row');
          var table = $('<table>').append(
            $('<thead>').append(
              $('<tr>').append(
                $('<td>').text(texts.get(N.TagRole))
              ).append($('<td>'))
            )
          );
          result['data'].forEach((name) => {
            var content = $('<tr>');
            content.append(
              $('<td>').text(name)
            );
            var operators = $('<td>');
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'bottom').
                attr('data-tooltip', texts.get(N.TagModify)).attr('onclick', 'showModifyRole("'+ name +'")').append(
                  $('<i>').addClass('material-icons').text('build')
                )
            );
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'bottom').
                attr('data-tooltip', texts.get(N.TagDelete)).attr('onclick', 'showRemoveRole("'+ name +'")').append(
                  $('<i>').addClass('material-icons').text('delete')
                )
            );
            content.append(operators);
            container.append(
              $('<div>').addClass('col m8 push-m2').append(
                table.append(content)
              )
            );
          });
          roleList.empty().append(container);
          $('.material-tooltip').remove();
          M.Tooltip.init($('.tooltipped'));
        }
      );
    }


    function showAddRole(){
      loadRoleInput();
      $('#role-button').attr('onclick', 'addRole()').append(
        $('<i>').addClass('material-icons right').text('add')
      ).append(
        texts.get(N.TagAdd)
      );
    }

    function addRole(){
      var rolename = $('#role-name').val();
      if (!rolename){
        M.toast({html: 'please input rolename'});
        return;
      }
      if (nameExp.test(rolename)){
        M.toast({html: "only letter/digit/'-'/'_'/'.' allowed in role name"});
        return;
      }
      var menu = new Array();
      $("input[name='menu']:checkbox:checked").each(function(){
        menu.push($(this).val());
      });
      var request = new Object();
      request.menu = menu;
      $.post(
        '/roles/'+ rolename,
        JSON.stringify(request),
        function(result){
          if (0 != result['error_code']) {
            M.toast({html: result['message']});
            return;
          }
          M.toast({html: 'role ' + rolename + ' added'});
          loadRoles();
          N.WriteOperateLog('add new role ' + rolename);
        },
        "json"
      );
    }

    function showModifyRole(roleName){
      $.getJSON(
        '/roles/' + roleName,
        function(result){
          if (0 != result['error_code']) {
            M.toast({html: result['message']});
            return;
          }
          if (!result['data']){
            M.toast({html: 'no role info available'});
            return;
          }
          var menu = result['data']['menu'];
          loadRoleInput(roleName, menu);
          $('#role-button').attr('onclick', 'modifyRole()').append(
            $('<i>').addClass('material-icons right').text('build')
          ).append(
            texts.get(N.TagModify)
          );
        }
      );
    }

    function modifyRole(){
      var rolename = $('#role-name').val();
      if (!rolename){
        M.toast({html: 'please input rolename'});
        return;
      }
      var menu = new Array();
      $("input[name='menu']:checkbox:checked").each(function(){
        menu.push($(this).val());
      });
      var request = new Object();
      request.menu = menu;
      $.ajax({
        url: '/roles/'+ rolename,
        method: "PUT",
        dataType: "json",
        data: JSON.stringify(request),
        success: function (result) {
          if (0 != result['error_code']) {
            M.toast({html: 'modify role fail: ' + result['message']});
            return;
          }
          M.toast({html: 'role ' + name + ' modified'});
          loadRoles();
          N.WriteOperateLog('modify role ' + name);
        },
        error: function (jqXHR, status, error) {
          M.toast({html: 'request modify role fail: ' + error, outDuration: 600});
        }
      });
    }

    function loadRoleInput(roleName, attachedMenu){
      var nameInput = $('<input>').attr('type', 'text').attr('id', 'role-name');
      if (roleName){
        nameInput.val(roleName).prop('readonly', true);
      }else{
        nameInput.attr('placeholder', 'Role Name')
      }
      var menuInput = $('<div>').addClass('row');
      menuList.forEach((item)=>{
        var itemValue = item[0];
        var itemName = item[1];
        menuInput.append(
          $('<div>').addClass('col m3').append(
            $('<label>').append(
              $('<input>').attr('type', 'checkbox').attr('name', 'menu').attr('id', 'menu-' + itemValue).val(itemValue)
            ).append(
              $('<span>').text(itemName)
            )
          )
        );
      });
      var panel = $('#content').empty();
      var content = $('<div>').addClass('row').append(
        $('<div>').addClass('col m10 push-m1').append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              nameInput
            ).append(
              $('<label>').attr('for', 'role-name').text(texts.get(N.TagRole))
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('col s4 m2 l2').append(
              $('<label>').text(texts.get(N.TagMenu))
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('col m8').append(
              menuInput
            )
          )
        )
      );
      var buttons = $('<div>').addClass('row').append(
        $('<div>').addClass('col m2').append(
          $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('onclick', 'loadRoles()').append(
            $('<i>').addClass('material-icons left').text('chevron_left')
          ).append(texts.get(N.TagBack))
        )
      ).append(
        $('<div>').addClass('col m2 right').append(
          $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('id', 'role-button')
        )
      )
      panel.append(
        $('<div>').addClass('section').append(content)
      ).append(
        $('<div>').addClass('divider')
      ).append(
        $('<div>').addClass('section').append(buttons)
      );
      if (attachedMenu){
        attachedMenu.forEach((menu)=>{
          $('#menu-' + menu).prop('checked', true);
        });
      }
      M.updateTextFields();
    }

    function showRemoveRole(name){
      $('#modal-content').empty().append(
        $('<h4>').text('Remove Role')
      ).append(
        $('<div>').text('Are you sure to remove role ' + name)
      );
      $('#modal-confirm').attr('onclick', 'removeRole("' + name + '")');
      var instance = M.Modal.getInstance($('#user-modal'));
      instance.open();
    }

    function removeRole(name) {
      $.ajax({
       url:'/roles/' + name,
       type: "DELETE",
       dataType: "json",
       success: function (result) {
           if (0 != result['error_code']) {
               M.toast({html: 'remove user role: ' + result['message'], outDuration: 1000});
               return;
           }
           M.toast({html: 'role "' + name + '" removed'})
           setTimeout(loadRoles, 500);
           N.WriteOperateLog('remove role ' + name);
       }
      });
    }

    //user groups
    function loadGroups(){
      var panel = $('#content').empty();
      panel.append(
        $('<div>').addClass('section').append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('col s4 m3 l2').append(
              $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('href', '#').attr('onclick', 'showAddGroup()').append(
                $('<i>').addClass('material-icons left').text('add')
              ).append(
                texts.get(N.TagAdd)
              )
            )
          )
        )
      ).append(
        $('<div>').addClass('divider')
      );
      var groupList = $('<div>').attr('id', 'group-list');
      panel.append(
        groupList
      );
      function outputMessage(message){
        groupList.empty().append(
          $('<div>').addClass('center').append(
            $('<span>').text(message)
          )
        );
      }

      $.getJSON(
        '/user_groups/',
        function(result){
          if (0 != result['error_code']) {
            outputMessage(result['message']);
            return;
          }
          if (!result['data']){
            outputMessage('no user group available');
            return
          }
          if (0 == result['data'].length){
            outputMessage('no user group available');
            return;
          }
          var container = $('<div>').addClass('row');
          var table = $('<table>').append(
            $('<thead>').append(
              $('<tr>').append(
                $('<td>').text(texts.get(N.TagUserGroup))
              ).append(
                $('<td>').text(texts.get(N.TagDisplayName))
              ).append(
                $('<td>').text(texts.get(N.TagMember))
              ).append($('<td>'))
            )
          );
          var currentGroup = N.GetCurrentGroup();
          result['data'].forEach((group) => {
            var content = $('<tr>');
            var groupName = group['name'];
            var displayName = group['display'];
            var memberCount = group['member'];

            content.append(
              $('<td>').text(groupName)
            ).append(
              $('<td>').text(displayName)
            ).append(
              $('<td>').text(memberCount)
            );
            var operators = $('<td>');
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'bottom').
                attr('data-tooltip', texts.get(N.TagModify)).attr('onclick', 'showModifyGroup("'+ groupName +'")').append(
                  $('<i>').addClass('material-icons').text('build')
                )
            );
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'bottom').
                attr('data-tooltip', texts.get(N.TagMember)).attr('onclick', 'showGroupMembers("'+ groupName +'")').append(
                  $('<i>').addClass('material-icons').text('group')
                )
            );
            if (groupName != currentGroup){
              operators.append(
                $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'bottom').
                  attr('data-tooltip', texts.get(N.TagDelete)).attr('onclick', 'showRemoveGroup("'+ groupName +'")').append(
                    $('<i>').addClass('material-icons').text('delete')
                  )
              );
            }

            content.append(operators);
            container.append(
              $('<div>').addClass('col m8 push-m2').append(
                table.append(content)
              )
            );
          });
          groupList.empty().append(container);
          $('.material-tooltip').remove();
          M.Tooltip.init($('.tooltipped'));
        }
      );
    }

    function showAddGroup(){
      loadGroupInput();
      $('#group-button').attr('onclick', 'addGroup()').append(
        $('<i>').addClass('material-icons right').text('add')
      ).append(
        texts.get(N.TagAdd)
      );
    }

    function addGroup(){
      var groupName = $('#group-name').val();
      if (!groupName){
        M.toast({html: 'please input group name'});
        return;
      }
      if (nameExp.test(groupName)){
        M.toast({html: "only letter/digit/'-'/'_'/'.' allowed in group name"});
        return;
      }
      var displayName = $('#display-name').val();

      var roleList = new Array();
      $("input[name='role']:checkbox:checked").each(function(){
        roleList.push($(this).val());
      });
      var request = new Object();
      request.display = displayName;
      request.role = roleList;
      $.post(
        '/user_groups/'+ groupName,
        JSON.stringify(request),
        function(result){
          if (0 != result['error_code']) {
            M.toast({html: result['message']});
            return;
          }
          M.toast({html: 'group ' + groupName + ' added'});
          loadGroups();
          N.WriteOperateLog('add new group ' + groupName);
        },
        "json"
      );
    }

    function showModifyGroup(groupName){
      $.getJSON(
        '/user_groups/' + groupName,
        function(result){
          if (0 != result['error_code']) {
            M.toast({html: result['message']});
            return;
          }
          if (!result['data']){
            M.toast({html: 'no group info available'});
            return;
          }
          var group = result['data'];
          var displayName = group['display'];
          var roles = group['role'];
          loadGroupInput(groupName, displayName, roles);
          $('#group-button').attr('onclick', 'modifyGroup()').append(
            $('<i>').addClass('material-icons right').text('build')
          ).append(
            texts.get(N.TagModify)
          );
        }
      );
    }

    function modifyGroup(){
      var groupName = $('#group-name').val();
      if (!groupName){
        M.toast({html: 'please input group name'});
        return;
      }
      var displayName = $('#display-name').val();

      var roleList = new Array();
      $("input[name='role']:checkbox:checked").each(function(){
        roleList.push($(this).val());
      });
      var request = new Object();
      request.display = displayName;
      request.role = roleList;
      $.ajax({
        url: '/user_groups/'+ groupName,
        method: "PUT",
        dataType: "json",
        data: JSON.stringify(request),
        success: function (result) {
          if (0 != result['error_code']) {
            M.toast({html: 'modify group fail: ' + result['message']});
            return;
          }
          M.toast({html: 'group ' + groupName + ' modified'});
          loadGroups();
          N.WriteOperateLog('modify group ' + groupName);
        },
        error: function (jqXHR, status, error) {
          M.toast({html: 'request modify group fail: ' + error, outDuration: 600});
        }
      });
    }

    function loadGroupInput(groupName, displayName, roles){
      var nameInput = $('<input>').attr('type', 'text').attr('id', 'group-name');
      if (groupName){
        nameInput.val(groupName).prop('readonly', true);
      }else{
        nameInput.attr('placeholder', 'Group Name');
      }
      var displayInput = $('<input>').attr('type', 'text').attr('id', 'display-name');
      if (displayName){
        displayInput.val(displayName);
      }else{
        displayInput.attr('placeholder', 'Display Name Of Group');
      }

      var roleInput = $('<div>').addClass('row');
      var panel = $('#content').empty();
      var content = $('<div>').addClass('row').append(
        $('<div>').addClass('col m10 push-m1').append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              nameInput
            ).append(
              $('<label>').attr('for', 'group-name').text(texts.get(N.TagUserGroup))
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              displayInput
            ).append(
              $('<label>').attr('for', 'display-name').text(texts.get(N.TagDisplayName))
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('col s4 m2 l2').append(
              $('<label>').text(texts.get(N.TagRole))
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('col m8').append(
              roleInput
            )
          )
        )
      );
      var buttons = $('<div>').addClass('row').append(
        $('<div>').addClass('col m2').append(
          $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('onclick', 'loadGroups()').append(
            $('<i>').addClass('material-icons left').text('chevron_left')
          ).append(texts.get(N.TagBack))
        )
      ).append(
        $('<div>').addClass('col m2 right').append(
          $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('id', 'group-button')
        )
      )
      panel.append(
        $('<div>').addClass('section').append(content)
      ).append(
        $('<div>').addClass('divider')
      ).append(
        $('<div>').addClass('section').append(buttons)
      );
      M.updateTextFields();

      function outputMessage(message){
        roleList.empty().append(
          $('<div>').addClass('center').append(
            $('<span>').text(message)
          )
        );
      }

      $.getJSON(
        '/roles/',
        function(result){
          if (0 != result['error_code']) {
            outputMessage(result['message']);
            return;
          }
          if (!result['data']){
            outputMessage('no role available');
            return
          }
          if (0 == result['data'].length){
            outputMessage('no role available');
            return;
          }
          result['data'].forEach((role)=>{
            roleInput.append(
              $('<div>').addClass('col m3').append(
                $('<label>').append(
                  $('<input>').attr('type', 'checkbox').attr('name', 'role').attr('id', 'role-' + role).val(role)
                ).append(
                  $('<span>').text(role)
                )
              )
            );
          });
          if (roles){
            roles.forEach((role)=>{
              $('#role-' + role).prop('checked', true);
            });
          }
        }
      );
    }

    function showRemoveGroup(name){
      $('#modal-content').empty().append(
        $('<h4>').text('Remove Group')
      ).append(
        $('<div>').text('Are you sure to remove group ' + name)
      );
      $('#modal-confirm').attr('onclick', 'removeGroup("' + name + '")');
      var instance = M.Modal.getInstance($('#user-modal'));
      instance.open();
    }

    function removeGroup(name) {
      $.ajax({
       url:'/user_groups/' + name,
       type: "DELETE",
       dataType: "json",
       success: function (result) {
           if (0 != result['error_code']) {
               M.toast({html: 'remove user group fail: ' + result['message'], outDuration: 1000});
               return;
           }
           M.toast({html: 'group "' + name + '" removed'})
           setTimeout(loadGroups, 500);
           N.WriteOperateLog('remove group ' + name);
       }
      });
    }

    function showGroupMembers(groupName){
      var panel = $('#content').empty();
      panel.append(
        $('<div>').addClass('section').append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('col s4 m3 l2').append(
              $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('href', '#').attr('onclick', 'showAddGroupMember("' + groupName + '")').append(
                $('<i>').addClass('material-icons left').text('add')
              ).append(
                texts.get(N.TagAdd)
              )
            )
          )
        )
      ).append(
        $('<div>').addClass('divider')
      );
      var userList = $('<div>').attr('id', 'user-list');
      panel.append(
        userList
      ).append(
        $('<div>').addClass('section').append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('col s4 m3 l2').append(
              $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('href', '#').attr('onclick', 'loadGroups()').append(
                $('<i>').addClass('material-icons left').text('chevron_left')
              ).append(
                texts.get(N.TagBack)
              )
            )
          )
        )
      );
      function outputMessage(message){
        userList.empty().append(
          $('<div>').addClass('center').append(
            $('<span>').text(message)
          )
        );
      }

      $.getJSON(
        '/user_groups/' + groupName + '/members/',
        function(result){
          if (0 != result['error_code']) {
            outputMessage(result['message']);
            return;
          }
          if (!result['data']){
            outputMessage('no member available');
            return
          }
          if (0 == result['data'].length){
            outputMessage('no member available');
            return;
          }
          var container = $('<div>').addClass('row');
          var table = $('<table>').append(
            $('<thead>').append(
              $('<tr>').append(
                $('<td>').text(texts.get(N.TagUser))
              ).append($('<td>'))
            )
          );
          result['data'].forEach((memberName) => {
            var content = $('<tr>');
            content.append(
              $('<td>').text(memberName)
            );
            var operators = $('<td>');
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'bottom').
                attr('data-tooltip', texts.get(N.TagDelete)).attr('onclick', 'showRemoveGroupMember("'+ groupName + '", "' + memberName +'")').append(
                  $('<i>').addClass('material-icons').text('delete')
                )
            );
            content.append(operators);
            container.append(
              $('<div>').addClass('col m8 push-m2').append(
                table.append(content)
              )
            );
          });
          userList.empty().append(container);
          $('.material-tooltip').remove();
          M.Tooltip.init($('.tooltipped'));
        }
      );
    }

    function showAddGroupMember(groupName){
      var nameInput = $('<input>').attr('type', 'text').attr('id', 'group-name').val(groupName).prop('readonly', true);
      var memberInput = $('<select>').attr('name', 'member').attr('id', 'option-member');
      var panel = $('#content').empty();
      var content = $('<div>').addClass('row').append(
        $('<div>').addClass('col m10 push-m1').append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              nameInput
            ).append(
              $('<label>').attr('for', 'group-name').text(texts.get(N.TagUserGroup))
            )
          )
        ).append(
          $('<div>').addClass('row').append(
            $('<div>').addClass('input-field col m6').append(
              memberInput
            ).append(
              $('<label>').attr('for', 'option-member').text(texts.get(N.TagMember))
            )
          )
        )
      );
      var buttons = $('<div>').addClass('row').append(
        $('<div>').addClass('col m2').append(
          $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('onclick', 'showGroupMembers("' + groupName + '")').append(
            $('<i>').addClass('material-icons left').text('chevron_left')
          ).append(texts.get(N.TagBack))
        )
      ).append(
        $('<div>').addClass('col m2 right').append(
          $('<a>').addClass('waves-effect waves-light blue-grey lighten-2 btn').attr('onclick', 'addGroupMember("' + groupName + '")').append(
            $('<i>').addClass('material-icons right').text('add')
          ).append(texts.get(N.TagAdd))
        )
      )
      panel.append(
        $('<div>').addClass('section').append(content)
      ).append(
        $('<div>').addClass('divider')
      ).append(
        $('<div>').addClass('section').append(buttons)
      );
      $.getJSON(
        '/user_search/',
        function(result){
          if (0 != result['error_code']) {
            M.toast({html: 'search user fail: ' + result['message']});
            return;
          }
          if (!result['data']){
            M.toast({html: 'no user available'});
            return
          }
          if (0 == result['data'].length){
            M.toast({html: 'no user available'});
            return;
          }
          result['data'].forEach((memberName) =>{
            memberInput.append(
              $('<option>').attr('value', memberName).text(memberName)
            );
          });
          M.FormSelect.init(memberInput);
        }
      );
      M.updateTextFields();
    }

    function addGroupMember(groupName){
      var memberName = $('#option-member').val();
      if (!memberName){
        M.toast({html: 'must choose a group member'});
        return;
      }
      $.post(
        '/user_groups/'+ groupName + '/members/' + memberName,
        "",
        function(result){
          if (0 != result['error_code']) {
            M.toast({html: result['message']});
            return;
          }
          M.toast({html: 'new member ' + memberName + ' added'});
          showGroupMembers(groupName);
          N.WriteOperateLog('add new member ' + memberName + ' to group ' + groupName);
        },
        "json"
      );
    }

    function showRemoveGroupMember(groupName, memberName){
      $('#modal-content').empty().append(
        $('<h4>').text('Remove Group Member')
      ).append(
        $('<div>').text('Are you sure to remove member '+ memberName +' from group ' + groupName)
      );
      $('#modal-confirm').attr('onclick', 'removeGroupMember("' + groupName + '", "' + memberName + '")');
      var instance = M.Modal.getInstance($('#user-modal'));
      instance.open();
    }

    function removeGroupMember(groupName, memberName) {
      $.ajax({
       url:'/user_groups/' + groupName + '/members/' + memberName,
       type: "DELETE",
       dataType: "json",
       success: function (result) {
           if (0 != result['error_code']) {
               M.toast({html: 'remove group member fail: ' + result['message'], outDuration: 1000});
               return;
           }
           M.toast({html: 'group member "' + memberName + '" removed'})
           setTimeout(showGroupMembers(groupName), 500);
           N.WriteOperateLog('remove member ' + memberName + ' from group ' + groupName);
       }
      });
    }

</script>
</body>
</html>
